package middleware

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net/http"
	"shop-common/library/serializer"
	"shop-common/library/variables"
	"shop-common/utils/contextArgs"
	"shop-security/token"
	"shop-sys/cache"
	"shop-sys/pkg/code"
	"strings"
	"time"
)

// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuth() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
		// 这里假设Token放在Header的Authorization中，并使用Bearer开头
		// 这里的具体实现方式要依据你的实际业务情况决定
		authHeader := ctx.Request.Header.Get("Authorization")
		if authHeader == "" {
			serializer.Echo(ctx, 2003, code.StatusText(code.TokenEmptyErr), nil)
			ctx.Abort()
			return
		}
		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			ctx.JSON(http.StatusUnauthorized, &serializer.Response{
				Code:    http.StatusUnauthorized,
				Result:  nil,
				Message: code.StatusText(code.TokenInvalidErr),
				Type:    "error",
				Time:    time.Now().Unix(),
			})
			ctx.Abort()
			return
		}

		claims, err := token.ParseToken(token.JwtSecret, parts[1])
		if err != nil {
			zap.L().Error("token解析失败", zap.Error(err))
			// token过期返回status = 401 && code = 401
			if err == token.TokenExpired {
				ctx.JSON(http.StatusUnauthorized, &serializer.Response{
					Code:    http.StatusUnauthorized,
					Result:  nil,
					Message: code.StatusText(code.TokenExpireErr),
					Type:    "error",
					Time:    time.Now().Unix(),
				})
				ctx.Abort()
				return
			}
			ctx.JSON(http.StatusUnauthorized, &serializer.Response{
				Code:    serializer.Code_ERROR,
				Result:  nil,
				Message: code.StatusText(code.TokenInvalidErr),
				Type:    "error",
				Time:    time.Now().Unix(),
			})
			ctx.Abort()
			return
		}

		// 获取redis缓存的user信息，对比判断是否合法。
		user, invalid := token.IsInvalid(claims, parts[1])
		if !invalid {
			ctx.JSON(http.StatusUnauthorized, &serializer.Response{
				Code:    serializer.Code_ERROR,
				Result:  nil,
				Message: code.StatusText(code.TokenInvalidErr),
				Type:    "error",
				Time:    time.Now().Unix(),
			})
			ctx.Abort()
			return
		}

		contextArgs.SetUserUserId(ctx, user.UserId)
		contextArgs.SetUserInternalId(ctx, user.Id)
		contextArgs.SetShopId(ctx, user.ShopId)

		// 获取当前用户角色信息
		role, err := cache.GetUserOnlineRole(variables.RedisConn, user.UserId)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, &serializer.Response{
				Code:    serializer.Code_ERROR,
				Result:  nil,
				Message: code.StatusText(code.TokenInvalidErr),
				Type:    "error",
				Time:    time.Now().Unix(),
			})
			ctx.Abort()
			return
		}
		ctx.Set("role", role)

		//perms, _ := business.ServiceImpl().SysUserService.FindByIdPermsList(ctx, user.Id)
		//ctx.Set("accessPerms", perms)
		//todo admin登录 context上 redis添加接口权限列表，这里需要从redis读取赋值到context上
		ctx.Next()
	}
}
